package org.dromara.tearoom.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.BeanUtils;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.tearoom.domain.*;
import org.dromara.tearoom.domain.bo.TerCouponBo;
import org.dromara.tearoom.domain.enums.*;
import org.dromara.tearoom.domain.vo.*;
import org.dromara.tearoom.mapper.*;
import org.dromara.tearoom.service.ITerCouponService;
import org.dromara.tearoom.util.WeekMaskUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Arrays.asList;
import static org.dromara.common.core.utils.CollectionUtils.*;

/**
 * 优惠劵Service业务层处理
 *
 * @author ckj
 * @date 2025-04-23
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class TerCouponServiceImpl implements ITerCouponService {

    private final TerCouponMapper baseMapper;

    private final TerCouponTemplateMapper couponTemplateMapper;

    private final TerUserMapper terUserMapper;

    private final TerOrderMapper orderMapper;

    private final TerGroupBuyMapper groupBuyMapper;

    private final TerRoomDetailsMapper roomDetailsMapper;


    /**
     * 查询优惠劵
     *
     * @param id 主键
     * @return 优惠劵
     */
    @Override
    public TerCouponVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }


    /**
     * 分页查询优惠劵列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 优惠劵分页列表
     */
    @Override
    public TableDataInfo<TerCouponVo> queryPageList(TerCouponBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TerCoupon> lqw = buildQueryWrapper(bo);
        Page<TerCouponVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的优惠劵列表
     *
     * @param bo 查询条件
     * @return 优惠劵列表
     */
    @Override
    public List<TerCouponVo> queryList(TerCouponBo bo) {
        LambdaQueryWrapper<TerCoupon> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<TerCoupon> buildQueryWrapper(TerCouponBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TerCoupon> lqw = Wrappers.lambdaQuery();
        lqw.orderByDesc(TerCoupon::getCreateTime);
        lqw.eq(bo.getTemplateId() != null, TerCoupon::getTemplateId, bo.getTemplateId());
        lqw.like(StringUtils.isNotBlank(bo.getName()), TerCoupon::getName, bo.getName());
        lqw.eq(bo.getUsePrice() != null, TerCoupon::getUsePrice, bo.getUsePrice());
        lqw.eq(bo.getTakeType() != null, TerCoupon::getTakeType, bo.getTakeType());
        lqw.eq(bo.getValidStartTime() != null, TerCoupon::getValidStartTime, bo.getValidStartTime());
        lqw.eq(bo.getValidEndTime() != null, TerCoupon::getValidEndTime, bo.getValidEndTime());
        lqw.eq(bo.getProductScope() != null, TerCoupon::getProductScope, bo.getProductScope());
        lqw.eq(bo.getDiscountPercent() != null, TerCoupon::getDiscountPercent, bo.getDiscountPercent());
        lqw.eq(bo.getDiscountPrice() != null, TerCoupon::getDiscountPrice, bo.getDiscountPrice());
        lqw.eq(bo.getDiscountLimitPrice() != null, TerCoupon::getDiscountLimitPrice, bo.getDiscountLimitPrice());
        lqw.eq(bo.getUserId() != null, TerCoupon::getUserId, bo.getUserId());
        lqw.eq(bo.getStatus() != null, TerCoupon::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getUseOrderId()), TerCoupon::getUseOrderId, bo.getUseOrderId());
        lqw.eq(bo.getUseTime() != null, TerCoupon::getUseTime, bo.getUseTime());
        lqw.eq(bo.getType() != null, TerCoupon::getType, bo.getType());
        lqw.eq(bo.getPlateType() != null, TerCoupon::getPlateType, bo.getPlateType());
        lqw.eq(bo.getHourCount() != null, TerCoupon::getHourCount, bo.getHourCount());
        if (StringUtils.isNotBlank(bo.getUserName())) {
            List<TerUserVo> terUserVoList = terUserMapper.selectVoList(new LambdaQueryWrapper<TerUser>().like(TerUser::getNickname, bo.getUserName()));
            if (CollUtil.isNotEmpty(terUserVoList)) {
                List<Long> memberUserIds = terUserVoList.stream().map(m -> m.getId()).collect(Collectors.toList());
                lqw.in(TerCoupon::getUserId, memberUserIds);
            } else {
                lqw.eq(TerCoupon::getUserId, 0L);
            }
        }
        if (StringUtils.isNotBlank(bo.getUserMobile())) {
            List<TerUserVo> terUserVoList = terUserMapper.selectVoList(new LambdaQueryWrapper<TerUser>().like(TerUser::getMobile, bo.getUserMobile()));
            if (CollUtil.isNotEmpty(terUserVoList)) {
                List<Long> memberUserIds = terUserVoList.stream().map(m -> m.getId()).collect(Collectors.toList());
                lqw.in(TerCoupon::getUserId, memberUserIds);
            } else {
                lqw.eq(TerCoupon::getUserId, 0L);
            }
        }
        if (ObjectUtil.isNotEmpty(params.get("createTimes"))) {
            List<String> createTimes = StrUtil.splitTrim(params.get("createTimes").toString(), ',');
            String startTime = createTimes.get(0);
            String endTime = createTimes.get(1);
            lqw.between(TerCoupon::getCreateTime, startTime, endTime);
        }
        return lqw;
    }

    /**
     * 新增优惠劵
     *
     * @param bo 优惠劵
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(TerCouponBo bo) {
        TerCoupon add = MapstructUtils.convert(bo, TerCoupon.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改优惠劵
     *
     * @param bo 优惠劵
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(TerCouponBo bo) {
        TerCoupon update = MapstructUtils.convert(bo, TerCoupon.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TerCoupon entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除优惠劵信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            List<TerCoupon> couponList = baseMapper.selectList(new LambdaQueryWrapper<TerCoupon>().in(TerCoupon::getId, ids));
            if (CollUtil.isNotEmpty(couponList)) {
                couponList.forEach(coupon -> {
                    // 减少优惠劵模板的领取数量 -1
                    couponTemplateMapper.updateCouponTemplateTakeCount(coupon.getTemplateId(), -1);
                });
            }
        }
        // 更新优惠劵
        Boolean deleteCount = baseMapper.delete(new LambdaQueryWrapper<TerCoupon>().in(TerCoupon::getId, ids).in(TerCoupon::getStatus, asList(CouponStatusEnum.UNUSED.getStatus(), CouponStatusEnum.EXPIRE.getStatus()))) > 0;
        if (!deleteCount) {
            throw new ServiceException("优惠卷回收失败");
        }
        return true;
    }

    /**
     * 第三方平台给用户发送优惠券
     * @param templateId   模版ID
     * @param groupBuyId    团购ID
     * @param userIds      用户编号列表
     * @return key: userId, value: 优惠券编号列表
     */
    @Override
    public Map<Long, List<Long>> takeCouponByGroupBy(Long templateId,Long groupBuyId, Set<Long> userIds, String remark) {
        return takeCoupon(templateId, userIds, CouponTakeTypeEnum.ADMIN, remark,groupBuyId);
    }

    /**
     * 领取优惠券
     *
     * @param templateId 优惠券模板编号
     * @param userIds    用户编号列表
     * @param takeType   领取方式
     * @return key: userId, value: 优惠券编号列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<Long, List<Long>> takeCoupon(Long templateId, Set<Long> userIds, CouponTakeTypeEnum takeType, String remark,Long groupBuyId) {
        TerCouponTemplateVo template = couponTemplateMapper.selectVoById(templateId);
        if (ObjectUtil.isEmpty(template)) {
            throw new ServiceException("优惠券模版没配置");
        }
        return takeCoupon(template, userIds, takeType, remark, groupBuyId);
    }

    /**
     * 使用优惠劵
     *
     * @param id      优惠劵编号
     * @param userId  用户编号
     * @param orderId 订单编号
     */
    @Override
    public void useCoupon(Long id, Long userId, String orderId) {
        // 校验状态
        TerCoupon coupon = baseMapper.selectOne(new LambdaQueryWrapper<TerCoupon>().eq(TerCoupon::getId, id).eq(TerCoupon::getUserId, userId));
        if (ObjectUtil.isEmpty(coupon)) {
            throw new ServiceException("优惠劵不存在");
        }
        if (ObjectUtil.notEqual(coupon.getStatus(), CouponStatusEnum.UNUSED.getStatus())) {
            throw new ServiceException("优惠劵不处于待使用状态");
        }
        // 校验有效期，为避免定时器没跑，实际优惠劵已经过期
        if (!DateUtil.isIn(new Date(), coupon.getValidStartTime(), coupon.getValidEndTime())) {
            throw new ServiceException("优惠券不在使用时间范围内");
        }
        // 更新状态
        coupon.setStatus(CouponStatusEnum.USED.getStatus());
        coupon.setUseTime(new Date());
        coupon.setUseOrderId(orderId);
        int updateCount = baseMapper.updateById(coupon);
        if (updateCount == 0) {
            throw new ServiceException("优惠劵不处于待使用状态");
        }
    }

    /**
     * 计算订单价格
     *
     * @param id
     * @param userId
     * @param orderId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TerOrderVo calculatePrice(Long id, Long userId, String orderId) {
        //加载用户的优惠劵列表
        List<TerCouponVo> coupons = baseMapper.selectVoList(new LambdaQueryWrapper<TerCoupon>().eq(TerCoupon::getUserId, userId).eq(TerCoupon::getStatus, CouponStatusEnum.UNUSED.getStatus()));
        coupons.removeIf(coupon -> DateUtil.compare(new Date(), coupon.getValidEndTime()) > 0);
        // 计算优惠劵的使用条件
        TerOrderVo orderVo = orderMapper.selectVoById(orderId);
        if (ObjectUtil.isEmpty(orderVo)) {
            throw new ServiceException("订单不存在!");
        }
        orderVo.setCoupons(calculateCoupons(coupons, orderVo));
        //计算优惠劵的使用条件
        if (ObjectUtil.isNotEmpty(id)) {
            TerOrderVo.Coupon couponBO = CollUtil.findOne(orderVo.getCoupons(), item -> item.getId().equals(id));
            TerCouponVo coupon = CollUtil.findOne(coupons, item -> item.getId().equals(id));
            if (couponBO == null || coupon == null) {
                throw new ServiceException("优惠劵不存在");
            }
            if (Boolean.FALSE.equals(couponBO.getMatch())) {
                throw new ServiceException(couponBO.getMismatchReason());
            }
            //计算优惠金额
            Integer couponPrice = getCouponPrice(coupon, orderVo.getTotalPrice());
            orderVo.setCouponPrice(couponPrice);
            orderVo.setPrepayAmount(orderVo.getTotalPrice() - couponPrice);
            //订单时长超过优惠时长
            if (CouponTypeEnum.XSJ.getType().equals(coupon.getType()) && orderVo.getPresetTime() <= coupon.getHourCount()) {
                orderVo.setCouponHour(coupon.getHourCount());
                orderVo.setPrepayAmount(0);
                orderVo.setRevenue(0);
                if(!CouponPlateTypeEnum.isZY(coupon.getPlateType()) && ObjectUtil.isNotEmpty(coupon.getGroupBuyId())){
                     TerGroupBuyVo groupBuyVo = groupBuyMapper.selectVoById(coupon.getGroupBuyId());
                     if(ObjectUtil.isNotEmpty(groupBuyVo)){
                         orderVo.setRevenue(groupBuyVo.getOriginalAmount());
                     }
                }
            }
            //记录使用的优惠劵
            orderVo.setCouponId(id);
            orderMapper.updateById(BeanUtil.toBean(orderVo, TerOrder.class));
        } else {
            orderVo.setPrepayAmount(orderVo.getTotalPrice());
            orderVo.setCouponId(null);
            orderVo.setCouponPrice(0);
            orderVo.setRevenue(orderVo.getTotalPrice());
            orderMapper.resetOrderPrice(orderVo);
        }
        return orderVo;
    }

    /**
     * 过期优惠券
     *
     * @return 过期数量
     */
    @Override
    public int expireCoupon() {
        // 1. 查询待过期的优惠券
        List<TerCoupon> list = baseMapper.selectList(new LambdaQueryWrapper<TerCoupon>().eq(TerCoupon::getStatus, CouponStatusEnum.UNUSED.getStatus()).le(TerCoupon::getValidEndTime, LocalDateTime.now()));
        if (CollUtil.isEmpty(list)) {
            return 0;
        }
        // 2. 遍历执行
        int count = 0;
        for (TerCoupon coupon : list) {
            try {
                boolean success = expireCoupon(coupon);
                if (success) {
                    count++;
                }
            } catch (Exception e) {
                log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId(), e);
            }
        }
        return count;
    }

    /**
     * 获取用户是否可以领取优惠券
     *
     * @param userId    用户编号
     * @param templates 优惠券列表
     * @return 是否可以领取
     */
    @Override
    public Map<Long, Boolean> getUserCanCanTakeMap(Long userId, List<TerCouponTemplateVo> templates) {
        // 1. 未登录时，都显示可以领取
        Map<Long, Boolean> userCanTakeMap = convertMap(templates, TerCouponTemplateVo::getId, templateId -> true);
        if (userId == null) {
            return userCanTakeMap;
        }

        // 2.1 过滤领取数量无限制的
        Set<Long> templateIds = convertSet(templates, TerCouponTemplateVo::getId, template -> template.getTakeLimitCount() != -1);
        // 2.2 检查用户领取的数量是否超过限制
        if (CollUtil.isNotEmpty(templateIds)) {
            Map<Long, Integer> couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId);
            for (TerCouponTemplateVo template : templates) {
                Integer takeCount = couponTakeCountMap.get(template.getId());
                userCanTakeMap.put(template.getId(), takeCount == null || takeCount < template.getTakeLimitCount());
            }
        }
        return userCanTakeMap;
    }

    /**
     * 获取用户是否拥有优惠券
     *
     * @param userId    用户编号
     * @param templates 优惠券列表
     * @return 是否可以领取
     */
    @Override
    public Map<Long, Boolean> getUserIsHaveMap(Long userId, List<TerCouponTemplateVo> templates) {
        // 1. 未登录时，都显示可以领取
        Map<Long, Boolean> userIsHaveMap = convertMap(templates, TerCouponTemplateVo::getId, templateId -> false);
        if (userId == null) {
            return userIsHaveMap;
        }
        Set<Long> templateIds = convertSet(templates, TerCouponTemplateVo::getId);
        if (CollUtil.isNotEmpty(templateIds)) {
            Map<Long, Integer> couponTakeCountMap = this.getTakeCountMapByTemplateIds(templateIds, userId);
            for (TerCouponTemplateVo template : templates) {
                Integer takeCount = couponTakeCountMap.get(template.getId());
                userIsHaveMap.put(template.getId(), takeCount != null && takeCount > 0);
            }
        }
        return userIsHaveMap;
    }

    /**
     * 统计会员领取优惠券的数量
     *
     * @param templateIds 优惠券模板编号列表
     * @param userId      用户编号
     * @return 领取优惠券的数量
     */
    @Override
    public Map<Long, Integer> getTakeCountMapByTemplateIds(Collection<Long> templateIds, Long userId) {
        if (CollUtil.isEmpty(templateIds)) {
            return Collections.emptyMap();
        }
        return baseMapper.selectCountByUserIdAndTemplateIdIn(userId, templateIds);
    }

    /**
     * 过期单个优惠劵
     *
     * @param coupon 优惠劵
     * @return 是否过期成功
     */
    private boolean expireCoupon(TerCoupon coupon) {
        // 更新记录状态
        TerCoupon newCoupon = new TerCoupon();
        newCoupon.setStatus(CouponStatusEnum.EXPIRE.getStatus());
        int updateRows = baseMapper.update(newCoupon, new LambdaUpdateWrapper<TerCoupon>().eq(TerCoupon::getId, coupon.getId()).eq(TerCoupon::getStatus, CouponStatusEnum.UNUSED.getStatus()));
        if (updateRows == 0) {
            log.error("[expireCoupon][coupon({}) 更新为已过期失败]", coupon.getId());
            return false;
        }
        log.info("[expireCoupon][coupon({}) 更新为已过期成功]", coupon.getId());
        return true;
    }

    private Map<Long, List<Long>> takeCoupon(TerCouponTemplateVo template, Set<Long> userIds, CouponTakeTypeEnum takeType, String remark,Long groupBuyId) {
        // 1. 过滤掉达到领取限制的用户
        removeTakeLimitUser(userIds, template, remark);
        // 2. 校验优惠劵是否可以领取
        validateCouponTemplateCanTake(template, userIds, takeType);
        // 3. 批量保存优惠劵
        List<TerCoupon> couponList = convertList(userIds, userId -> convert(template, userId));
        couponList.stream().forEach(coupon -> {
            coupon.setCreateTime(new Date());
            coupon.setUpdateTime(new Date());
            coupon.setRemark(remark);
            coupon.setGroupBuyId(groupBuyId);
        });
        baseMapper.insertBatch(couponList);
        // 4. 增加优惠劵模板的领取数量
        couponTemplateMapper.updateCouponTemplateTakeCount(template.getId(), userIds.size());
        return convertMultiMap(couponList, TerCoupon::getUserId, TerCoupon::getId);
    }

    /**
     * 过滤掉达到领取上线的用户
     *
     * @param userIds        用户编号数组
     * @param couponTemplate 优惠劵模版
     */
    private void removeTakeLimitUser(Set<Long> userIds, TerCouponTemplateVo couponTemplate, String remark) {
        if (couponTemplate.getTakeLimitCount() <= 0) {
            return;
        }
        // 查询已领过券的用户
        List<TerCoupon> alreadyTakeCoupons = baseMapper.selectList(new LambdaQueryWrapper<TerCoupon>().eq(TerCoupon::getTemplateId, couponTemplate.getId()).in(TerCoupon::getUserId, userIds));
        if (CollUtil.isEmpty(alreadyTakeCoupons)) {
            return;
        }
        // 移除达到领取限制的用户
        Map<Long, Integer> userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, TerCoupon::getUserId, Collectors.summingInt(c -> 1));
        userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount());
    }

    /**
     * 校验优惠券是否可以领取
     *
     * @param couponTemplate 优惠券模板
     * @param userIds        领取人列表
     * @param takeType       领取方式
     */
    private void validateCouponTemplateCanTake(TerCouponTemplateVo couponTemplate, Set<Long> userIds, CouponTakeTypeEnum takeType) {
        // 如果所有用户都领取过，则抛出异常
        if (CollUtil.isEmpty(userIds)) {
            throw new ServiceException("用户已领取过此优惠券");
        }
        // 校验模板
        if (couponTemplate == null) {
            throw new ServiceException("优惠劵模板不存在");
        }
        // 校验剩余数量
        if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), TerCouponTemplate.TIME_LIMIT_COUNT_MAX) // 非不限制
                && couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
            throw new ServiceException("当前剩余数量不够领取");
        }
        // 校验"固定日期"的有效期类型是否过期
        if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplate.getValidityType())) {
            if (DateUtil.compare(couponTemplate.getValidEndTime(), new Date()) < 0) {
                throw new ServiceException("优惠券已过期");
            }
        }
        // 校验领取方式
        if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getType())) {
            throw new ServiceException("领取方式不正确");
        }
    }


    TerCoupon convert(TerCouponTemplateVo template, Long userId) {
        TerCoupon coupon = BeanUtil.copyProperties(template, TerCoupon.class, "id");
        coupon.setTemplateId(template.getId());
        coupon.setStatus(CouponStatusEnum.UNUSED.getStatus());
        coupon.setUserId(userId);
        if (CouponTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) {
            coupon.setValidStartTime(template.getValidStartTime());
            coupon.setValidEndTime(template.getValidEndTime());
        }
        if (CouponTemplateValidityTypeEnum.TERM.getType().equals(template.getValidityType())) {
            coupon.setValidStartTime(DateUtils.addDays(new Date(), template.getFixedStartTerm()));
            coupon.setValidEndTime(DateUtils.addDays(new Date(), template.getFixedEndTerm()));
        }
        return coupon;
    }

    /**
     * 计算用户的优惠劵列表（可用 + 不可用）
     *
     * @param coupons 优惠劵
     * @param orderVo 计算结果
     * @return 优惠劵列表
     */
    private List<TerOrderVo.Coupon> calculateCoupons(List<TerCouponVo> coupons, TerOrderVo orderVo) {
        return convertList(coupons, coupon -> {
            TerOrderVo.Coupon matchCoupon = BeanUtils.toBean(coupon, TerOrderVo.Coupon.class);
            matchCoupon.setMatch(false);
            //优惠劵未到使用时间
            if (DateUtil.compare(new Date(), coupon.getValidStartTime()) < 0) {
                matchCoupon.setMismatchReason("优惠劵未到使用时间");
                return matchCoupon;
            }
            //优惠劵没有匹配的商品
            if (!isMatchCouponOrderItems(orderVo, coupon)) {
                matchCoupon.setMismatchReason("优惠劵没有匹配的商品");
                return matchCoupon;
            }
            //差 %1$,.2f 元可用优惠劵
            Integer totalPayPrice = orderVo.getTotalPrice();
            if (totalPayPrice < coupon.getUsePrice()) {
                matchCoupon.setMismatchReason(String.format("差 %1$,.2f 元可用优惠劵", (coupon.getUsePrice() - totalPayPrice) / 100D));
                return matchCoupon;
            }
            //优惠金额超过订单金额
            Integer couponPrice = getCouponPrice(coupon, totalPayPrice);
            if (couponPrice >= totalPayPrice) {
                matchCoupon.setMismatchReason("优惠金额超过订单金额");
                return matchCoupon;
            }
            //订单时长超过优惠时长
            if (CouponTypeEnum.XSJ.getType().equals(coupon.getType())) {
                if (orderVo.getPresetTime() > coupon.getHourCount()) {
                    matchCoupon.setMismatchReason("订单时长超过优惠时长");
                    return matchCoupon;
                }
            }
            // 检查当前星期是否可用
            if (coupon.getValidDays() != null && coupon.getValidDays() != 0) {
                // 使用位运算检查当前星期是否可用
                if (WeekMaskUtils.isNowValid(coupon.getValidDays())) {
                    matchCoupon.setMismatchReason("当前日期不可使用该优惠券");
                    return matchCoupon;
                }
            }
            //检查当前时间是否在可用时间段内
            if (ObjectUtil.isAllNotEmpty(coupon.getUseStartTime(), coupon.getUseEndTime())) {
                LocalTime currentTime = LocalDateTime.now().toLocalTime();
                // 处理跨天情况（如 22:00 - 02:00）
                if (coupon.getUseEndTime().isBefore(coupon.getUseStartTime())) {
                    // 跨天时间范围：当前时间 >= 开始时间 OR 当前时间 <= 结束时间
                    if (!(currentTime.isAfter(coupon.getUseStartTime()) ||
                            currentTime.isAfter(LocalTime.MAX)) ||  // 当前时间在开始时间之后（当天）
                            !(currentTime.isBefore(coupon.getUseEndTime()) ||
                                    currentTime.isBefore(LocalTime.MIDNIGHT))) { // 当前时间在结束时间之前（次日）
                        matchCoupon.setMismatchReason("当前时间不可使用该优惠券");
                        return matchCoupon;
                    }
                } else {
                    // 普通时间范围：开始时间 <= 当前时间 <= 结束时间
                    if (currentTime.isBefore(coupon.getUseStartTime()) ||
                            currentTime.isAfter(coupon.getUseEndTime())) {
                        matchCoupon.setMismatchReason("当前时间不可使用该优惠券");
                        return matchCoupon;
                    }
                }
            }
            //满足条件
            matchCoupon.setMatch(true);
            return matchCoupon;
        });
    }

    /**
     * 判断优惠劵可使用的订单
     *
     * @param orderVo 订单
     * @param coupon  优惠劵
     * @return 订单项（商品）列表
     */
    private Boolean isMatchCouponOrderItems(TerOrderVo orderVo, TerCouponVo coupon) {
        if (CouponProductScopeTypeEnum.MD.getType().equals(coupon.getProductScope())) {
            TerRoomDetailsVo roomDetailsVo = roomDetailsMapper.selectVoById(orderVo.getTearoomId());
            if (ObjectUtil.isEmpty(roomDetailsVo)) {
                return false;
            }
            if (!coupon.getProductScopeValues().contains(roomDetailsVo.getGroupId())) {
                return false;
            }
        }
        if (CouponProductScopeTypeEnum.SP.getType().equals(coupon.getProductScope())) {
            if (!coupon.getProductScopeValues().contains(orderVo.getTearoomId())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 计算优惠金额
     *
     * @param coupon
     * @param totalPayPrice
     * @return
     */
    public Integer getCouponPrice(TerCouponVo coupon, Integer totalPayPrice) {
        // 减价
        if (CouponTypeEnum.DJJ.getType().equals(coupon.getType())) {
            return coupon.getDiscountPrice();
        }
        // 打折
        if (CouponTypeEnum.ZKJ.getType().equals(coupon.getType())) {
            int couponPrice = totalPayPrice - (totalPayPrice * coupon.getDiscountPercent() / 100);
            // 优惠上限
            return coupon.getDiscountLimitPrice() == null ? couponPrice : Math.min(couponPrice, coupon.getDiscountLimitPrice());
        }
        return 0;
    }


}
